import { throttle } from "./utils/index";
import { changePoint } from "./event";
import DrawArrow from "./element/arrow";

let elementList = []; //页面上所有的元素
let toolBar = { pannel: [] };
let hoverElement = "";
let drugElement = "";
let ArrowElement = "";
let isdruging = false;
let isArrowing = false;

class Draw {
    constructor(id) {
        this.canvas = document.getElementById(id); //TODO: 这里做容错
        this.ctx = this.canvas.getContext("2d");
        // hoverElement = ""; // 当前元素是否选中
        // 鼠标点击事件
        canvas.onmousedown = this.onmousedown.bind(this);
        canvas.onmousemove = throttle(this.onmousemove.bind(this), 50);
    }
    /**
     * 鼠标hover事件
     * @param {*} e
     */
    onmousemove(e) {
        var x = e.clientX - canvas.offsetLeft;
        var y = e.clientY - canvas.offsetTop;
        // 是否拖动某个元素
        if (isdruging && hoverElement && !isArrowing) {
            // 这里的x和y为相对canvas的坐标
            console.log(`x:${x},y: ${y}`);
            // 计算偏移后位置
            if (typeof hoverElement.drug == 'function') {
                hoverElement.x = x - hoverElement.offsetX;
                hoverElement.y = y - hoverElement.offsetY;
                // 计算边缘点位坐标
                hoverElement.drug();
            }
        } else if (hoverElement) {
            hoverElement.isCurrent = false;
        }

        // 是否为箭头
        if (isArrowing && ArrowElement) {
            console.log("【箭头】正在绘制：");
            ArrowElement.drug(0, 0, x, y);
            // ArrowElement.toX = x;
            // ArrowElement.toY = y;
        }
        hoverElement = null;

        this.reDraw(e);
    }
    /**
     * 鼠标按下事件
     * @param {*} e
     */
    onmousedown(e) {
        // 是否命中某个目标元素
        if (hoverElement && (hoverElement.onmousedown || hoverElement.drug)) {
            isdruging = true;
            hoverElement.isCurrent = false;
            // 计算偏移量
            hoverElement.offsetX =
                e.clientX - this.canvas.offsetLeft - hoverElement.x;
            hoverElement.offsetY =
                e.clientY - this.canvas.offsetTop - hoverElement.y;
            // 执行对应的方法
            hoverElement.onmousedown && hoverElement.onmousedown();
        }

        // 点击背景, 取消工具栏的展示
        if (!hoverElement) {
            toolBar.pannel = [];
        }

        hoverElement = null;
        this.reDraw(e);

        document.onmouseup = this.onmouseup.bind(this);
    }
    onmouseup(e) {
        // 展示pannel :TODO: ~~~~~~~~~ ！！！！！！ ~~~~~~~~~~
        if (ArrowElement && (!hoverElement)) {
            toolBar.pannel = [];
            drawPannel(e.clientX - this.canvas.offsetLeft, e.clientY - this.canvas.offsetTop, ArrowElement);
        }
        if (hoverElement && hoverElement.onmouseup) {
            hoverElement.onmouseup();
        }
        isdruging = false;
        drugElement = null;
        hoverElement = null;
        isArrowing = false;
        ArrowElement = "";
        this.reDraw(e);
    }
}

/**
 * 绘制背景图
 */
Draw.prototype.drawBg = function () {
    const context = this.ctx;
    function drawGrid(color, stepx, stepy) {
        context.save();
        context.fillStyle = "white";
        // console.log(context);
        context.fillRect(0, 0, context.canvas.width, context.canvas.height);
        context.lineWidth = 0.5;
        context.strokeStyle = color;
        for (var i = 0; i <= context.canvas.width; i += stepx) {
            context.beginPath();
            context.moveTo(i, 0);
            context.lineTo(i, context.canvas.height);
            context.closePath();
            context.stroke();
        }
        for (var j = 0; j <= context.canvas.height; j += stepy) {
            context.beginPath();
            context.moveTo(0, j);
            context.lineTo(context.canvas.width, j);
            context.closePath();
            context.stroke();
        }
        context.restore();
    }
    drawGrid("#ccc", 20, 20);
};

let index = 1;
class BaseElement {
    constructor({ x, y, r = 0, width, height, color, type, text }) {
        this.id = `${type}_${index++}`;
        this.type = type;
        this.x = x;
        this.y = y;
        this.r = r;
        this.width = width;
        this.height = height;
        this.parent = null;
        this.ArrowList = []; //所有箭头
        this.text = text;
        this.color = color || "#999999";
        this.canvas = document.getElementById("canvas"); //TODO: 这里做容错
        this.ctx = this.canvas.getContext("2d");
        this.editTagList = [];
        // 绘制图形
        this.render = this.render.bind(this);
        this.drawSpecial = this.drawSpecial.bind(this);
        this.hover = this.hover.bind(this);
    }
    /**
     * 公共渲染方法
     * @param {*} ctx
     * @param {*} x 光标所在的x位置
     * @param {*} y 光标所在的y位置
     */
    render(x, y) {
        // console.log("this is render");
        // 是否是常规组件
        this.drawSpecial();

        if (
            (x &&
                y &&
                this.ctx.isPointInPath(x, y) &&
                (!hoverElement || this.type == "EditTagElement")) ||
            this.isCurrent
        ) {
            // console.log("这块区域被光标选中", this.type);
            if (isdruging) {
                this.ctx.fillStyle = "#fefefe";
            }
            hoverElement = this;
            // this.isCurrent = true; //当前元素被选中
            // this.ctx.fill();
            this.hover && this.hover(x, y);
        } else if (!hoverElement) {
            changePoint("default");
        }
    }
    /**
     * 每个元素私有的渲染方法
     */
    drawSpecial() { }
    hover() {
        // console.log("this is hover1");
        changePoint("move");
    }
    drug() {
        console.log("this is drug");
    }
    initEditTag(x, y) {
        console.log("【initEditTag】");
        let positionList = [
            {
                x: this.x + this.width / 2 - this.r,
                y: this.y - this.r,
            },
            {
                x: this.x + this.width - this.r,
                y: this.y + this.height / 2 - this.r,
            },
            {
                x: this.x + this.width / 2 - this.r,
                y: this.y + this.height - this.r,
            },
            {
                x: this.x - this.r,
                y: this.y + this.height / 2 - this.r,
            },
        ];

        positionList.forEach((tag, index) => {
            let editTag = new EditTagElement({ x: tag.x, y: tag.y });
            editTag.parent = this;
            this.editTagList[index] = editTag;
        });
    }
    moveEditTag(x, y) {
        console.log("【moveEditTag】");
        if (!x || !y) {
            throw new Error("坐标不能为零");
            return;
        }
        this.x = x;
        this.y = y;
        let positionList = [
            {
                x: this.x + this.width / 2 - this.r,
                y: this.y - this.r,
            },
            {
                x: this.x + this.width - this.r,
                y: this.y + this.height / 2 - this.r,
            },
            {
                x: this.x + this.width / 2 - this.r,
                y: this.y + this.height - this.r,
            },
            {
                x: this.x - this.r,
                y: this.y + this.height / 2 - this.r,
            },
        ];

        positionList.forEach((tag, index) => {
            this.editTagList[index].x = tag.x;
            this.editTagList[index].y = tag.y;
            //
            this.editTagList[index].drug(tag.x, tag.y);
        });
    }

}

/**
 * 绘制长方形
 * @param {*} x
 * @param {*} y
 * @param {*} width
 * @param {*} height
 * @param {*} color
 */
class RectElement extends BaseElement {
    constructor(props) {
        props.type = "RectElement";
        super(props);
        this.initEditTag.call(this);
    }
    drawSpecial() {
        this.ctx.moveTo(this.x, this.y);
        this.ctx.beginPath();
        this.ctx.rect(this.x, this.y, this.width, this.height);
        this.ctx.font = "16px Verdana";
        if (this.text) {
            this.ctx.fillText(this.text, this.x + 20, this.y + this.height / 2);
        }
        this.ctx.stroke();
        this.ctx.closePath();
    }
    hover() {
        super.hover();
        this.editTagList.forEach((ele) => {
            ele.render();
        });
    }
    drug() {
        console.log("%s is druging", this.id);
        this.moveEditTag(this.x, this.y);
    }
}

Draw.prototype.drawRect = function (x, y, width, height, text) {
    let rect = new RectElement({ x, y, width, height, text });
    rect.render();
    elementList.push(rect);
    return rect;
};
/**
 * 绘制圆形
 * @param {*} x
 * @param {*} y
 * @param {*} width
 * @param {*} height
 * @param {*} color
 */

class CircleElement extends BaseElement {
    constructor(props) {
        props.type = "CircleElement";
        super(props);
        this.r = props.r;
        this.text = props.text;
        this.initEditTag.call(this);
    }
    drawSpecial() {
        this.ctx.beginPath();
        this.ctx.moveTo(this.x + this.r, this.y);
        this.ctx.arc(this.x, this.y, this.r, 2 * Math.PI, 0, true);
        if (this.text) {
            this.ctx.font = "16px Verdana";
            this.ctx.fillText(this.text, this.x - 20, this.y + 6);
        }
        this.ctx.closePath();
        this.ctx.stroke();
    }
    hover(x, y) {
        super.hover();
        this.editTagList.forEach((ele) => {
            ele.render(x, y);
        });
    }
    render() {
        const args = Array.prototype.slice.call(arguments);
        super.render.apply(this, args);

        // 渲染editTag
    }
    drug() {
        console.log("%s is druging", this.id);
        this.moveEditTag(this.x, this.y);
        // this.moveArrow(this.x, this.y);
    }
}

/**
 * 元素周围的小圆圈，具有扩展功能
 */
class EditTagElement extends BaseElement {
    constructor(props) {
        const radius = 8; // 设置半径大小
        super({
            x: props.x,
            y: props.y,
            width: 2 * radius,
            height: 2 * radius,
            type: "EditTagElement",
            r: radius,
            color: "00f",
        });
        this.r = radius;
    }
    drawSpecial() {
        this.ctx.save();
        this.ctx.beginPath();
        this.ctx.moveTo(this.x + this.r, this.y);
        this.ctx.arc(this.x, this.y, this.r, 2 * Math.PI, 0, true);
        this.ctx.fillStyle = "#0f0";
        this.ctx.closePath();
        this.ctx.stroke();
        this.ctx.fill();
        this.ctx.restore();
    }
    hover() {
        console.log("EditTagElement hover");
        if (isArrowing && ArrowElement && (ArrowElement.startElement != this)) {
            this.ctx.fillStyle = '#f00';
            this.ctx.fill();
        }
        isdruging = false;
        isArrowing = true;
        changePoint("crosshair");
    }
    onmousedown() {
        // 是否开始箭头
        if (isArrowing) {
            console.log("准备绘制箭头");
            // 计算当前点在父元素的位置
            let position = 0;
            hoverElement.parent.editTagList.forEach((tag, index) => {
                if (hoverElement.x == tag.x && hoverElement.y == tag.y) {
                    position = index;
                }
            });
            // 开始绘图
            let arrow = new DrawArrow({
                fromX: hoverElement.x,
                fromY: hoverElement.y,
                toX: hoverElement.x,
                toY: hoverElement.y,
            });
            hoverElement.ArrowList.push(arrow); // 此时hoverElement 指的是 editTag
            arrow.direction = position;
            arrow.startElement = hoverElement;
            ArrowElement = arrow;
            elementList.push(arrow);
        }
    }
    onmouseup() {
        // 是否是当前节点
        if (isArrowing && ArrowElement && (ArrowElement.startElement != this)) {
            console.log("！！！找到目标点", ArrowElement.id)
            ArrowElement.toX = this.x;
            ArrowElement.toY = this.y;
            ArrowElement.endElement = this;
            this.ArrowList.push(ArrowElement);
        }
    }
    drug(x, y) {
        console.log("EditTagElement is drug");
        this.ArrowList.forEach((arrow) => {
            if (arrow.startElement == this) {
                arrow.drug(x, y);
            } else if (arrow.endElement == this) {
                arrow.drug(0, 0, x, y);
            } else {
                console.log("都不是")
            }

        });
    }

}

/**
 * 画圆形
 * @param {*} x
 * @param {*} y
 * @param {*} r
 */

Draw.prototype.drawCircle = function (x, y, r, text) {
    let circle = new CircleElement({ x, y, width: 2 * r, height: 2 * r, r, text });
    circle.render();
    elementList.push(circle);
    return circle;
};

/**
 * 重新渲染所有的组件
 * @param {*} e
 */
Draw.prototype.reDraw = function (e) {
    e = e || event;
    var x = e.clientX - this.canvas.offsetLeft;
    var y = e.clientY - this.canvas.offsetTop;

    this.canvas.width = this.canvas.width;
    if (this.ctx) {
        // 绘制背景
        this.drawBg();
        // 显示所有的工具栏
        Object.keys(toolBar).forEach((tool) => {
            let tools = toolBar[tool];
            if (Array.isArray(tools)) {
                for (var i = 0; i < tools.length; i++) {
                    var c = tools[i];
                    c.render(x, y);
                }
            } else if (typeof tools == "object") {
                tools.render(x, y);
            }
        });
        // 显示所有的自定义控件
        for (var i = 0; i < elementList.length; i++) {
            var c = elementList[i];
            c.render(x, y);
        }
    }
};

function drawPannel(x, y, ArrowElement) {
    // 绘制工具栏
    let bg = new RectElement({ x, y, width: 300, height: 200 });
    bg.drug = null;
    bg.hover = null;
    let clickBtn = new RectElement({
        x: x + 20,
        y: y + 20,
        width: 100,
        height: 60,
        text: "点击",
    });
    clickBtn.onmousedown = function () {
        let newRect = Draw.prototype.drawRect(x, y, 100, 60, '点击');
        toolBar.pannel = [];
        ArrowElement.endElement = newRect.editTagList[ArrowElement.direction];
        newRect.editTagList[ArrowElement.direction].ArrowList.push(ArrowElement);
    }
    let scrollBtn = new CircleElement({
        x: x + 70,
        y: y + 150,
        r: 40,
        text: "滚动",
    });
    scrollBtn.onmousedown = function () {
        let newRect = Draw.prototype.drawCircle(x + 40, y, 40, '滚动');
        toolBar.pannel = [];
        ArrowElement.endElement = newRect.editTagList[ArrowElement.direction];
        newRect.editTagList[ArrowElement.direction].ArrowList.push(ArrowElement);
    }
    toolBar.pannel = [clickBtn, scrollBtn, bg,];
    // elementList = elementList.concat([bg, clickBtn, scrollBtn]);
}

export default Draw;
